package com.javandad.app.server.servlet;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.javandad.app.client.searchComponent.SearchService;
import com.javandad.app.server.db.DatabaseManager;
import com.javandad.app.server.db.PMFSingleton;
import com.javandad.app.shared.entity.User;
import com.javandad.app.shared.entity.UserGroup;
import com.javandad.app.shared.entity.project.Project;
import com.javandad.app.shared.entity.search.AdvancedProjectSearchProperties;
import com.javandad.app.shared.entity.search.AdvancedUserSearchProperties;
import com.javandad.app.shared.entity.search.FreetextSearchProperties;
import com.javandad.app.shared.entity.search.SearchProperties;
import com.javandad.app.shared.entity.search.SearchResult;

/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class SearchServiceImpl extends RemoteServiceServlet implements SearchService {
	DatabaseManager dbm = DatabaseManager.getDefaultDatabaseManager();

	@Override
	public List<SearchResult> search(SearchProperties search) throws IllegalArgumentException {
		if (search instanceof FreetextSearchProperties) {
			FreetextSearchProperties fsp = (FreetextSearchProperties) search;
			PersistenceManager pm = PMFSingleton.getPM();
			LinkedList<SearchResult> results = new LinkedList<SearchResult>();
			switch (fsp.getType()) {
			case FreetextSearchProperties.SEARCH_FOR_USER:
				results.addAll(findUser(fsp, pm));
				break;

			case FreetextSearchProperties.SEARCH_FOR_PROJECT:
				results.addAll(findProject(fsp, pm));
				break;

			case FreetextSearchProperties.SEARCH_FOR_GROUP:
				results.addAll(findGroup(fsp, pm));
				break;

			case FreetextSearchProperties.SEARCH_FOR_ALL:
				results = new LinkedList<SearchResult>();
				results.addAll(findUser(fsp, pm));
				results.addAll(findProject(fsp, pm));
				results.addAll(findGroup(fsp, pm));
				break;
			}
			pm.close();
			
			
			return results;
		} else
			throw new IllegalArgumentException();
	}

	public Set<SearchResult> findUser(FreetextSearchProperties search, PersistenceManager pm) throws IllegalArgumentException {
		Set<SearchResult> results = new HashSet<SearchResult>();

		// freetext search
		Set<User> users = new HashSet<User>();
		String searchString = search.getFreetext();
		if (searchString == null)
			searchString = new String("");
		else
			searchString = searchString.trim();
		boolean emptyFreetext = searchString.isEmpty() || searchString.equals("");
		if (!emptyFreetext) {
			String[] words = searchString.split(" ");
			for (String word : words)
				freetextUserSearch(word, users, pm);
		}else{

			users.addAll(DatabaseManager.getDefaultDatabaseManager().getUsers(pm));
			
		}

        
		if (search instanceof AdvancedUserSearchProperties) {
			AdvancedUserSearchProperties opts = (AdvancedUserSearchProperties) search;
			if (opts.anythingSet()) {
				for (User user : users)
					if (filterUserResult(user, opts))
						results.add(user);
			} else
				results.addAll(users);
		} else 
			results.addAll(users);
		

		return results;
	}

	private void freetextUserSearch(String word, Set<User> results, PersistenceManager pm) {
		// username
		List<User> byUsername = dbm.getUsersByParameter("username", word, pm);
		results.addAll(byUsername);
		// firstName
		List<User> byFirstName = dbm.getUsersByParameter("firstName", word, pm);
		results.addAll(byFirstName);
		// lastName
		List<User> byLastName = dbm.getUsersByParameter("lastName", word, pm);
		results.addAll(byLastName);
		// email
		List<User> byEmail = dbm.getUsersByParameter("email", word, pm);
		results.addAll(byEmail);
	}

	private boolean filterUserResult(User user, AdvancedUserSearchProperties opts) {
		if (opts.getCreationDateStart() != null)
			if (user.getCreationDate().before(opts.getCreationDateStart()))
				return false;
		if (opts.getCreationDateEnd() != null)
			if (user.getCreationDate().after(opts.getCreationDateEnd()))
				return false;
		if (opts.getEmail() != null && !opts.getEmail().equals(""))
			if (!user.getEmail().equalsIgnoreCase(opts.getEmail()))
				return false;
		if (opts.getCountries() != null && !opts.getCountries().isEmpty()) {
			boolean found = false;
			for (String country : opts.getCountries())
				if (user.getCountry() != null && user.getCountry().equalsIgnoreCase(country)) {
					found = true;
					break;
				}
			if (!found)
				return false;
		}
		if (opts.getCities() != null && !opts.getCities().isEmpty()) {
			boolean found = false;
			for (String city : opts.getCities())
				if (user.getCity() != null && user.getCity().equalsIgnoreCase(city)) {
					found = true;
					break;
				}
			if (!found)
				return false;
		}
		return true;
	}

	private Set<SearchResult> findGroup(FreetextSearchProperties search, PersistenceManager pm) {
		// freetext search on groups
		Set<SearchResult> results = new HashSet<SearchResult>();

		// find group by groupURL
		try {
			if ( search.getFreetext() != null && !search.getFreetext().isEmpty()){
			UserGroup byURL = pm.getObjectById(UserGroup.class, search.getFreetext());
			results.add(byURL);
			}else{
				results.addAll( DatabaseManager.getDefaultDatabaseManager().getUserGroups(pm));
			}
		} catch (JDOObjectNotFoundException e) {
		}

		return results;
	}

	private Set<SearchResult> findProject(FreetextSearchProperties search, PersistenceManager pm) {
		Set<SearchResult> results = new HashSet<SearchResult>();

		// freetext search
		Set<Project> projects = new HashSet<Project>();
		String searchString = search.getFreetext();
		if (searchString == null)
			searchString = new String("");
		else
			searchString = searchString.trim();
		boolean emptyFreetext = searchString.isEmpty() || searchString.equals("");
		if (!emptyFreetext) {
			String[] words = searchString.split(" ");
			for (String word : words)
				freetextProjectSearch(word, projects, pm);
		}else{
			projects.addAll(DatabaseManager.getDefaultDatabaseManager().getProjects(pm));
		}

		if (search instanceof AdvancedProjectSearchProperties) {
			AdvancedProjectSearchProperties opts = (AdvancedProjectSearchProperties) search;
			if (opts.anythingSet()) {
				for (Project project : projects)
					if (filterProjectResult(project, opts))
						results.add(project);
			}
			else
				results.addAll(projects);
		} else 
			results.addAll(projects);

		return results;
	}

	private void freetextProjectSearch(String word, Set<Project> results, PersistenceManager pm) {
		try {
			Project byName = pm.getObjectById(Project.class, word);
			if (byName != null)
			  results.add(byName);
		} catch (JDOObjectNotFoundException e) {
		}
	}

	private boolean filterProjectResult(Project project, AdvancedProjectSearchProperties opts) {
		if (opts.getProjectType() != 0)
			if (project.getProjectType() != opts.getProjectType())
				return false;
		return true;
	}

}
